package com.dexafree.materialList.listeners;

import ohos.agp.components.VelocityDetector;
import ohos.multimodalinput.event.TouchEvent;

/**
 * 手势识别器
 *
 * @author hw
 * @since 2021/5/26
 */
public class GestureDetector {
    /**
     * 手势监听
     */
    public interface OnGestureListener {
        /**
         * 发生滚动时回调
         *
         * @param e1        手指按下时的事件
         * @param e2        手指移动时的事件
         * @param distanceX 横向的移动距离
         * @param distanceY 纵向的移动距离
         * @return 是否滑动
         */
        boolean onScroll(TouchEvent e1, TouchEvent e2, float distanceX, float distanceY);

        void onDoubleTap();
    }

    private int mTouchSlopSquare;
    private final OnGestureListener mListener;

    private boolean mAlwaysInTapRegion;

    private TouchEvent mCurrentDownEvent;

    private float mLastFocusX;
    private float mLastFocusY;
    private float mDownFocusX;
    private float mDownFocusY;

    private VelocityDetector mVelocityTracker;
    //	双击的最大间隔时间
    private int doubleTapTimeout;
    private int tapCount = 0;
    private long firstTapTime = 0;

    public GestureDetector(OnGestureListener listener) {
        mListener = listener;
        int touchSlop = ComponentConfiguration.getScaledTouchSlop();
        // 滑动的时候，手指的移动要大于这个距离才算发生了滚动
        mTouchSlopSquare = touchSlop * touchSlop;
        doubleTapTimeout = ComponentConfiguration.getDoubleTapTimeout();
    }

    /**
     * 触摸事件
     *
     * @param ev 触摸对象
     * @return 是否拦截
     */
    public boolean onTouchEvent(TouchEvent ev) {
        final int action = ev.getAction();
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityDetector.obtainInstance();
        }
        mVelocityTracker.addEvent(ev);

        final boolean pointerUp =
                action == TouchEvent.OTHER_POINT_UP;
        final int skipIndex = pointerUp ? ev.getIndex() : -1;

        float sumX = 0;
        float sumY = 0;
        final int count = ev.getPointerCount();
        // 把所有还在触摸的手指的位置x，y加起来，后面求平均数，算出中心焦点
        for (int i = 0; i < count; i++) {
            if (skipIndex == i) {
                // 跳过非主要指针的抬起动作
                continue;
            }
            sumX += (double) ev.getPointerPosition(i).getX();
            sumY += (double) ev.getPointerPosition(i).getY();
        }
        final int div = pointerUp ? count - 1 : count;
        // 求平均值，算出中心焦点
        final float focusX = sumX / div;
        final float focusY = sumY / div;
        boolean handled = false;
        switch (action) {
            case TouchEvent.OTHER_POINT_DOWN:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                break;

            case TouchEvent.OTHER_POINT_UP:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                break;

            case TouchEvent.PRIMARY_POINT_DOWN:
                mDownFocusX = mLastFocusX = focusX;
                mDownFocusY = mLastFocusY = focusY;
                mCurrentDownEvent = ev;
                mAlwaysInTapRegion = true;
                break;

            case TouchEvent.POINT_MOVE:
                final float scrollX = (float) (mLastFocusX - (double)focusX);
                final float scrollY = (float) (mLastFocusY - (double)focusY);
                if (mAlwaysInTapRegion) {
                    final int deltaX = (int) (focusX - (double)mDownFocusX);
                    final int deltaY = (int) (focusY - (double)mDownFocusY);
                    int distance = (deltaX * deltaX) + (deltaY * deltaY);
                    int slopSquare = mTouchSlopSquare;

                    if (distance > slopSquare) {
                        handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                        mLastFocusX = focusX;
                        mLastFocusY = focusY;
                        mAlwaysInTapRegion = false;
                    }
                } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
                    mLastFocusX = focusX;
                    mLastFocusY = focusY;
                }
                break;

            case TouchEvent.PRIMARY_POINT_UP:
                if (firstTapTime != 0 && System.currentTimeMillis() - firstTapTime <= doubleTapTimeout) {
                    tapCount++;
                    if (tapCount == 1) {
                        mListener.onDoubleTap();
                        firstTapTime = 0;
                        tapCount = 0;
                    }
                    break;
                }
                firstTapTime = System.currentTimeMillis();
                break;

            case TouchEvent.CANCEL:
                break;
        }
        return handled;
    }

    /**
     * 监听
     */
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener,
            OnContextClickListener {
        /**
         * onSingleTapUp
         *
         * @param e e
         * @return onSingleTapUp
         */
        public boolean onSingleTapUp(TouchEvent e) {
            return false;
        }

        /**
         * onLongPress
         *
         * @param e TouchEvent
         */
        public void onLongPress(TouchEvent e) {
        }

        /**
         * 是否可滚动
         *
         * @param e1        手指按下时的事件
         * @param e2        手指移动时的事件
         * @param distanceX 横向的移动距离
         * @param distanceY 纵向的移动距离
         * @return onScroll
         */
        public boolean onScroll(TouchEvent e1, TouchEvent e2,
                                float distanceX, float distanceY) {
            return false;
        }

        @Override
        public void onDoubleTap() {
        }

        /**
         * onFling
         *
         * @param e1        手指按下时的事件
         * @param e2        手指移动时的事件
         * @param velocityX 横向的移动速度
         * @param velocityY 纵向的移动速度
         * @return onFling
         */
        public boolean onFling(TouchEvent e1, TouchEvent e2, float velocityX, float velocityY) {
            return false;
        }

        /**
         * onShowPress
         *
         * @param e TouchEvent
         */
        public void onShowPress(TouchEvent e) {
        }

        /**
         * onDown
         *
         * @param e TouchEvent
         * @return onDown
         */
        public boolean onDown(TouchEvent e) {
            return false;
        }

        /**
         * onDoubleTap
         *
         * @param e TouchEvent
         * @return onDoubleTap
         */
        public boolean onDoubleTap(TouchEvent e) {
            return false;
        }

        /**
         * 是否doubleTapEvent
         *
         * @param e TouchEvent
         * @return onDoubleTapEvent
         */
        public boolean onDoubleTapEvent(TouchEvent e) {
            return false;
        }

        /**
         * onSingleTapConfirmed
         *
         * @param e TouchEvent
         * @return onSingleTapConfirmed
         */
        public boolean onSingleTapConfirmed(TouchEvent e) {
            return false;
        }

        /**
         * 是否可点击
         *
         * @param e TouchEvent
         * @return onContextClick
         */
        public boolean onContextClick(TouchEvent e) {
            return false;
        }
    }

    /**
     * 监听
     */
    public interface OnDoubleTapListener {
        boolean onSingleTapConfirmed(TouchEvent e);

        boolean onDoubleTap(TouchEvent e);

        boolean onDoubleTapEvent(TouchEvent e);
    }

    /**
     * OnContextClickListener
     */
    public interface OnContextClickListener {
        boolean onContextClick(TouchEvent e);
    }

}
